--[[
    @Author       : baidwwy
    @Date         : 2021-02-11 11:49:09
    @LastEditTime : 2021-02-18 10:11:16
--]]

local adler32       = require("zlib").adler32
local m_pack        = require("cmsgpack").pack
local m_unpack      = require("cmsgpack.safe").unpack

local c_isyieldable = coroutine.isyieldable--lua5.3
local c_runing      = coroutine.running
local c_yield       = coroutine.yield
local c_resume      = coroutine.resume
local c_create      = coroutine.create
local t_unpack      = table.unpack
local PackClient = package.loaded.PackClient or require("HPS/PackClient")
local RPCClient = class("RPCClient",PackClient)

local REG = setmetatable({}, {__mode="k"})
local CB  = setmetatable({}, {__mode="k"})

function RPCClient:RPCClient()
    PackClient.PackClient(self)--初始化父类
    local reg = {}
    REG[self] = reg--private  注册表
    CB[self]  = {}--private  回调表
    return setmetatable({}, {
        __newindex = function ( t,k,v )
            if type(v)=="function" then
                reg[k] = v
                reg[adler32(k)] = v
            end
        end,
        __index = reg
    })
end

function RPCClient:__index(k)--调用方法
    local co,main = c_runing()
    local hash = adler32(k)
    if co and not main and c_isyieldable() then--如果有协程，则有返回值
        return function (self,...)
            local cp = adler32(tostring(co))
            CB[self][cp] = co --TODO:超时
            self._hp:Send(m_pack{hash,cp,...})
            return c_yield()
        end
    end
    return function (self,...)
        self._hp:Send(m_pack{hash,0,...}) 
    end
end

function RPCClient:发送(...)
    return self._hp:Send(m_pack{...})
end

local function cofunc(self,cp,func,...)
    self._hp:Send(m_pack{0,cp,func(self,...)})
end

function RPCClient:_数据事件(id,data)
    local t = m_unpack(data)
    if type(t)=='table' then
        local hash,cp = t[1],t[2]
        if hash==0 then--返回
            local co = CB[self][cp]
            if co then
                CB[self][cp] = nil
                local r,err = c_resume(co, t_unpack(t,3))
                if not r then
                    warn(err)
                end
            end
        else
            local func = REG[self][hash]
            if func then
                if cp==0 then--没有返回
                    func(self,t_unpack(t,3))
                else
                    local co = c_create(cofunc)
                    local r,err = c_resume(co,self,cp,func,t_unpack(t,3))
                    if not r then
                        warn(err)
                        self._hp:Send(m_pack{0,cp,nil})
                    end
                end
            elseif cp~=0 then
                self._hp:Send(m_pack{0,cp,nil})
            end
        end
    elseif self.数据事件 then
        self:数据事件(id,data)
    end
end

return RPCClient